function BoListTable(listtable_id, table, bations, ractions, pk, uri) {
    this.api = uri;
    this.id = listtable_id;
    this.pk = pk;
    this.dataTables = table;
    this.barActions = bations;
    this.rowActions = ractions;
}
// panel is `form` or `table`
BoListTable.prototype.show = function(panel) {
        if (panel === undefined) {
            return;
        }
        if (panel === 'form') {
            document.getElementById(this.id + "_forms").reset();
            $(this.id + "_forms").find("input:hidden").val("");
            $('#' + this.id + '_listtable_box').hide();
            $('#' + this.id + '_forms_box').show();
        } else if (panel === 'table') {
            $('#' + this.id + '_listtable_box').show();
            $('#' + this.id + '_forms_box').hide();
        }
    };
    // fill form data from ajax response.
    // data is js object type.
BoListTable.prototype.fill_form = function(data, callback) {
    $("#" + this.id + "_forms").find('.form-control').each(function() {
        var elem_name = $(this).attr("name");
        if (elem_name !== undefined || elem_name !== null || $.trim(elem_name) !== "") {
            if (data.hasOwnProperty(elem_name)) {
                var remote_v = data[elem_name];
                var data_type = $(this).attr("type");
                if (data_type === "radio") {
                    $('input[name="' + elem_name + '"]').each(function() {
                        $(this).prop("checked", false);
                        var v = $(this).val();
                        if ($.inArray(v, remote_v) !== -1) {
                            $(this).prop("checked", true);
                        }
                    });
                } else if (data_type === "checkbox") {
                    $(this).prop("checked", false);
                    var v = $(this).val();
                    if ($.inArray(v, remote_v) !== -1) {
                        $(this).prop("checked", true);
                    }
                } else {
                    try {
                        $(this).val(remote_v);
                    } catch (e) {}
                }
            }
        }
    });
    if (callback !== undefined) {
        callback(data);
    }
};
BoListTable.prototype.buildActionsBar = function(actions) {
    var html = '<select id="' + this.id + '_batch_actions_select" class="form-control">';
    html += '<option value="-1">批量操作</option>';

    for (var k = 0; k < actions.length; k++) {
        var menu = actions[k];
        if (menu.length < 2) {
            continue;
        }
        if (menu.length < 3) {
            menu[menu.length] = {
                "before_bulk_actions": "",
                "after_bulk_actions": ""
            }
        } else {
            if (menu[2].before_bulk_actions === undefined) {
                menu[2].before_bulk_actions = "";
            }
            if (menu[2].after_bulk_actions === undefined) {
                menu[2].after_bulk_actions = "";
            }
        }
        html += '<option value="' + actions[k][0] + '" data-before_bulk_actions="' + menu[2].before_bulk_actions + '" data-after_bulk_actions="' + menu[2].after_bulk_actions + '">' + actions[k][1] + '</option>';
    }
    html += '<select>';
    html += '<button type="button" class="btn btn-default btn-sm" id="' + this.id + '_actions_bar_apply_btn" style="margin-left:5px;">应用</button>';
    return html;
};
BoListTable.prototype.buildActionsRow = function(title, row, menus) {
    var html = '<div class="dropdown">';
    html += '<a href="#" data-toggle="dropdown" class="dropdown-toggle" role="button" aria-haspopup="true" aria-expanded="false">' + title + '<span class="caret"></span></a>';
    html += '<ul class="dropdown-menu" role="menu">';
    for (var k = 0; k < menus.length; k++) {
        var menu = menus[k];
        if (menu.length < 2) {
            continue;
        }
        if (menu.length < 3) {
            menu[menu.length] = {
                "before_row_action": "",
                "after_row_action": ""
            }
        } else {
            if (menu[2].before_row_action === undefined) {
                menu[2].before_row_action = "";
            }
            if (menu[2].after_row_action === undefined) {
                menu[2].after_row_action = "";
            }
        }
        if (menu === "|" || menu[0] === "|") {
            html += '<li class="divider"></li>'
        } else {
            html += '<li><a href="javascript:void(0);" class="bo_datatables_row_action_item" data-id="' + row[this.pk] + '" data-action="' + menu[0] + '" data-before_row_action="' + menu[2].before_row_action + '" data-after_row_action="' + menu[2].after_row_action + '">' + menu[1] + '</a></li>';
        }
    }
    html += '</ul>';
    html += '</div>';
    return html;
};
BoListTable.prototype.bindRowAction = function() {
    var self_id = this.id;
    var self = this;
    $("#" + self_id).on('click', '.bo_datatables_row_action_item', function() {
        var data = $(this).data();
        var params = { "action_name": data['action'], "primary_keys": [data['id']], "bo_listtable_behavior": "do-action" };
        var hook_before_func = data['before_row_action'];
        var pass = true;
        if (hook_before_func.length > 0) {
            pass = eval(hook_before_func)(params, self.api);
        }
        if (pass) {
            $.post(self.api, bo_xsrf(params), function(rsp) {
                var hook_after_func = data['after_row_action'];
                var pass_r = true;
                if (hook_after_func.length > 0) {
                    pass_r = eval(hook_after_func)(rsp, params, self.api);
                }
                if (pass_r && rsp.success) {
                    bo_alert_success(rsp.message);
                    self.dataTables.ajax.reload(null, false);
                } else {
                    bo_alert_error(rsp.message);
                }
            }, "json");
        }
    });
};
BoListTable.prototype.init = function() {
    var self = this;
    var self_id = this.id;
    var table = this.dataTables;
    $("#" + self_id + "_listtable_add_btn").click(function() {
        self.show('form');
    });
    $("#" + self_id + "_forms_save_and_exit_btn").click(function() {
        self.show('table');
        var cb = $(this).parent().data();
        var before_cb = cb['beforeSave'];
        var after_cb = cb['afterSave'];
        if (before_cb !== undefined && $.trim(before_cb)!=="") {
            var func = eval(before_cb);
            func('save_and_exit');
        }
        $.post(self.api, $("#" + self_id + "_forms").serialize(), function(rsp) {
            if (rsp.success) {
                if (after_cb !== undefined && $.trim(after_cb)!=="") {
                    var func = eval(after_cb);
                    func('save_and_exit', rsp);
                }
                bo_alert_success(rsp.message);
                table.ajax.reload(null, false);
            } else {
                bo_valid_errors(self_id + '_forms', rsp.data, rsp.message)
            }

        }, "json");
    });
    $('#' + self_id + '_forms_save_and_edit_btn').click(function() {
        var cb = $(this).parent().data();
        var before_cb = cb['beforeSave'];
        var after_cb = cb['afterSave'];
        if (before_cb !== undefined && $.trim(before_cb)!=="") {
            var func = eval(before_cb);
            func('save_and_edit');
        }
        $.post(self.api, $("#" + self_id + "_forms").serialize(), function(rsp) {
            if (rsp.success) {
                self.fill_form(rsp.data);
                if (after_cb !== undefined && $.trim(after_cb)!=="") {
                    var func = eval(after_cb);
                    func('save_and_edit', rsp);
                }
                bo_alert_success(rsp.message);
                table.ajax.reload(null, false);
            } else {
                bo_valid_errors(self_id + '_forms', rsp.data, rsp.message)
            }
        }, "json");
    });
    $('#' + self_id + '_forms_save_and_new_btn').click(function() {
        var cb = $(this).parent().data();
        var before_cb = cb['beforeSave'];
        var after_cb = cb['afterSave'];
        if (before_cb !== undefined && $.trim(before_cb)!=="") {
            var func = eval(before_cb);
            func('save_and_new');
        }
        $.post(self.api, $("#" + self_id + "_forms").serialize(), function(rsp) {
            if (rsp.success) {
                document.getElementById(self_id + "_forms").reset();
                $(self_id + "_forms").find("input:hidden").val("");
                if (after_cb !== undefined && $.trim(after_cb)!=="") {
                    var func = eval(after_cb);
                    func('save_and_new', rsp);
                }
                bo_alert_success(rsp.message);
                table.ajax.reload(null, false);
            } else {
                bo_valid_errors(self_id + '_forms', rsp.data, rsp.message)
            }
        }, "json");
    });
    if (this.barActions !== undefined && this.barActions !== null && this.barActions.length > 0) {
        $('#' + self_id + '_wrapper').find("div.bo_datatables_actions_bar").html(this.buildActionsBar(this.barActions));
        $("#" + self_id + "_actions_bar_apply_btn").click(function() {
            var dropdown = $("#" + self_id + "_batch_actions_select");
            var action = dropdown.val();
            if (action !== "-1") {
                var opt = dropdown.find("option:selected");
                var data = opt.data();
                var primary_keys = [];
                $("#" + self_id ).find(".bo_datatables_row_checkbox").each(function() {
                    var sel = $(this);
                    var name = sel.attr("name");
                    if (name !== undefined && name === self.pk) {
                        if (sel.prop('checked')) {
                            primary_keys[primary_keys.length] = sel.val();
                        }
                    }
                });
                var params = { "action_name": action, "primary_keys": primary_keys, "bo_listtable_behavior": "do-action" };
                var hook_before_func = data['before_bulk_actions'];
                var pass = true;
                if (hook_before_func.length > 0) {
                    pass = eval(hook_before_func)(params, self.api);
                }
                if (pass) {
                    $.post(self.api, bo_xsrf(params), function(rsp) {
                        var hook_after_func = data['after_bulk_actions'];
                        var pass_r = true;
                        if (hook_before_func.length > 0) {
                            pass_r = eval(hook_after_func)(rsp, params, rsp);
                        }
                        if (pass_r && rsp.success) {
                            bo_alert_success(rsp.message);
                            self.dataTables.ajax.reload(null, false);
                        } else {
                            bo_alert_error(rsp.message);
                        }
                    }, "json");
                }
            }
        });
    }
};